﻿using System;
using System.Data;
using System.Reflection;

using vJine.Core.IoC;

namespace vJine.Core.ORM {
    /// <summary>
    /// 类型映射特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class MapAttribute : Attribute {

        /// <summary>
        /// 将实体类型映射特性转换为配置文件实体类型映射
        /// </summary>
        /// <param name="map">实体类型映射特性</param>
        /// <returns>配置文件实体类型映射</returns>
        public static implicit operator OrmConfig.Map(MapAttribute map) {
            return new OrmConfig.Map() {
                active = true
                , Name = map.Name, Alias = map.Alias
                , IsPrimary = map.IsPrimary,  UniqueName = map.UniqueName

                , IsNullable = map.IsNullable, IsIgnored = map.IsIgnored, TrimString = map.TrimString

                , SQL_TYPE = map.SQL_TYPE, DbType  = map.DbType

                , Conv = map.Conv

            };
        }

        /// <summary>
        /// 实例化类型映射特性
        /// </summary>
        public MapAttribute() {
        }

        /// <summary>
        /// 实例化实体类型映射特性
        /// </summary>
        /// <param name="Alias">属性别名</param>
        public MapAttribute(string Alias) {
            this.Alias = Alias;
        }

        /// <summary>
        /// 属性名
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 属性别名
        /// </summary>
        internal string Alias { get; set; }

        internal string name_alias { get; set; }
        /// <summary>
        /// 是否主键
        /// </summary>
        public bool IsPrimary { get; set; }
        /// <summary>
        /// 唯一键名称
        /// </summary>
        public string UniqueName { get; set; }
        /// <summary>
        /// 是否可空
        /// </summary>
        public bool IsNullable { get; set; }
        /// <summary>
        /// 是否忽略
        /// </summary>
        public bool IsIgnored { get; set; }
        /// <summary>
        /// 是否Trim字符串
        /// </summary>
        public bool TrimString { get; set; }
        /// <summary>
        /// 数据库SQL类型
        /// </summary>
        public string SQL_TYPE { get; set; }
        /// <summary>
        /// 数据库参数类型
        /// </summary>
        public DbType? DbType { get; set; }
        private Type _Conv;
        /// <summary>
        /// 类型转换类
        /// </summary>
        public Type Conv {
            get {
                return this._Conv;
            }
            set {
                if (value == null) {
                    this._Conv = null; this.Conv_I = null; this.Conv_Q = null;
                    return;
                }

                bool HasPropertyName = false;
                Type paramType = typeof(Type);

                this.Conv_I = 
                    GetMethod(value, "CONV_I", ref HasPropertyName, ref paramType);
                this.I_HasPropertyName = HasPropertyName;
                this.IparamType = paramType;

                this.Conv_Q = 
                    GetMethod(value, "CONV_Q", ref HasPropertyName, ref paramType);
                this.Q_HasPropertyName = HasPropertyName;
                this.QparamType = paramType;

                this._Conv = value;
            }
        }

        /// <summary>
        /// 插入转换方法是否包含属性名
        /// </summary>
        public bool I_HasPropertyName { get; private set; }
        /// <summary>
        /// 插入转换方法
        /// </summary>
        public MethodInfo Conv_I { get; internal set; }
        /// <summary>
        /// 传入专访方法参数类型
        /// </summary>
        public Type IparamType { get; private set; }

        /// <summary>
        /// 读出转换方法是否包含属性名
        /// </summary>
        public bool Q_HasPropertyName { get; private set; }
        /// <summary>
        /// 读出转换方法
        /// </summary>
        public MethodInfo Conv_Q { get; internal set; }
        /// <summary>
        /// 读出转换方法参数类型
        /// </summary>
        public Type QparamType { get; private set; }

        static MethodInfo GetMethod(Type Converter, string Name, ref bool HasPropertyName, ref Type objType) {

            HasPropertyName = false;
            MethodInfo converter = 
                Converter.GetMethod(Name, BindingFlags.Public | BindingFlags.Static);
            if(converter == null) {
                return null;
            } else {
                ParameterInfo[] PI = converter.GetParameters();
                if(PI.Length == 1) {
                    HasPropertyName = false;

                    objType = PI[0].ParameterType;
                    return converter;
                } else if(PI.Length == 2) {
                    if(PI[1].ParameterType == Reflect.@string) {
                        HasPropertyName = true;

                        objType = PI[0].ParameterType;
                        return converter;
                    } else {
                        return null;
                    }
                } else {
                    return null;
                }
            }
        }
    }
}
